#ifndef xpack_math_expe
#define xpack_math_expe
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::math_expe::inc
#include"define/base_type.hpp"
#include"define/inf.hpp"
#include"macro/xexport.hpp"
#include"meta/is_same.hpp"
#pragma pop_macro("xuser")

namespace mixc::math_expe{
    constexpr uxx mask_low                 = 32 - 1;
    constexpr uxx shift                    = 5;
    constexpr f64 f64_lut_een0_een31    [] = {1.000000000000000000e+00, 3.678794411714423412e-01, 1.353352832366127063e-01, 4.978706836786395092e-02, 1.831563888873418419e-02, 6.737946999085468888e-03, 2.478752176666359214e-03, 9.118819655545165475e-04, 3.354626279025119815e-04, 1.234098040866796086e-04, 4.539992976248487568e-05, 1.670170079024566908e-05, 6.144212353328213680e-06, 2.260329406981055889e-06, 8.315287191035685032e-07, 3.059023205018260324e-07, 1.125351747192592103e-07, 4.139937718785170402e-08, 1.522997974471264301e-08, 5.602796437537273201e-09, 2.061153622438560020e-09, 7.582560427911915196e-10, 2.789468092868928072e-10, 1.026187963170190286e-10, 3.775134544279102570e-11, 1.388794386496403906e-11, 5.109089028063331784e-12, 1.879528816539085994e-12, 6.914400106940213306e-13, 2.543665647376926833e-13, 9.357622968840189535e-14, 3.442477108469982134e-14, };
    constexpr f64 f64_lut_een32_een704  [] = {1.000000000000000000e+00, 1.266416554909419728e-14, 1.603810890548643312e-28, 2.031092662734821295e-42, 2.572209372642432337e-56, 3.257488532207548981e-70, 4.125337404615226527e-84, 5.224395583791782093e-98, 6.616261056709575339e-112, 8.378942533819497308e-126, 1.061123153746369187e-139, 1.343823928702095386e-153, 1.701840870191749322e-167, 2.155239451832284156e-181, 2.729430921594307562e-195, 3.456596504588705494e-209, 4.377491037053170650e-223, 5.543727118291739396e-237, 7.020667798504949778e-251, 8.891089926546138647e-265, 1.125982347416640661e-278, 1.425962685304203427e-292, 1.805862751352334343e-306, };
    constexpr f32 f32_lut_een0_een88    [] = {
        1.00000000e+00f, 3.67879441e-01f, 1.35335283e-01f, 4.97870684e-02f, 1.83156389e-02f, 6.73794700e-03f, 2.47875218e-03f, 9.11881966e-04f, 3.35462628e-04f, 1.23409804e-04f, 4.53999298e-05f, 1.67017008e-05f, 6.14421235e-06f, 2.26032941e-06f, 8.31528719e-07f, 3.05902321e-07f, 
        1.12535175e-07f, 4.13993772e-08f, 1.52299797e-08f, 5.60279644e-09f, 2.06115362e-09f, 7.58256043e-10f, 2.78946809e-10f, 1.02618796e-10f, 3.77513454e-11f, 1.38879439e-11f, 5.10908903e-12f, 1.87952882e-12f, 6.91440011e-13f, 2.54366565e-13f, 9.35762297e-14f, 3.44247711e-14f, 
        1.26641655e-14f, 4.65888615e-15f, 1.71390843e-15f, 6.30511676e-16f, 2.31952283e-16f, 8.53304763e-17f, 3.13913279e-17f, 1.15482242e-17f, 4.24835426e-18f, 1.56288219e-18f, 5.74952226e-19f, 2.11513104e-19f, 7.78113224e-20f, 2.86251858e-20f, 1.05306174e-20f, 3.87399763e-21f, 
        1.42516408e-21f, 5.24288566e-22f, 1.92874985e-22f, 7.09547416e-23f, 2.61027907e-23f, 9.60268005e-24f, 3.53262857e-24f, 1.29958143e-24f, 4.78089288e-25f, 1.75879220e-25f, 6.47023493e-26f, 2.38026641e-26f, 8.75651076e-27f, 3.22134029e-27f, 1.18506486e-27f, 4.35961000e-28f, 
        1.60381089e-28f, 5.90009054e-29f, 2.17052201e-29f, 7.98490425e-30f, 2.93748211e-30f, 1.08063928e-30f, 3.97544974e-31f, 1.46248623e-31f, 5.38018616e-32f, 1.97925988e-32f, 7.28129018e-33f, 2.67863696e-33f, 9.85415469e-34f, 3.62514092e-34f, 1.33361482e-34f, 4.90609473e-35f, 
        1.80485139e-35f, 6.63967720e-36f, 2.44260074e-36f, 8.98582594e-37f, 3.30570063e-37f, 1.21609930e-37f, 4.47377931e-38f, 1.64581143e-38f, 6.05460190e-39f, 
    };
}

namespace mixc::math_expe::origin{
    template<class f64_t>
    requires(inc::is_same<f64_t, f64>)
    inline f64 exper_unsafe(uxx x){
        return f64_lut_een0_een31[x & mask_low] * f64_lut_een32_een704[x >> shift];
    }

    template<class f64_t>
    requires(inc::is_same<f64_t, f64>)
    inline f64 exper(uxx x){
        if (x >= sizeof(f64_lut_een0_een31) / sizeof(f64_lut_een0_een31[0]) * sizeof(f64_lut_een32_een704) / sizeof(f64_lut_een32_een704[0])){
            return inc::inf_pos;
        }
        return exper_unsafe<f64>(x);
    }

    template<class f32_t>
    requires(inc::is_same<f32_t, f32>)
    inline f32 exper_unsafe(uxx x){
        return f32_lut_een0_een88[x];
    }

    template<class f32_t>
    requires(inc::is_same<f32_t, f32>)
    inline f32 exper(uxx x){
        if (x >= sizeof(f32_lut_een0_een88) / sizeof(f32_lut_een0_een88[0])){
            return f32(inc::inf_pos);
        }
        return exper_unsafe<f32>(x);
    }
}

#endif

xexport_space(mixc::math_expe::origin)